package logic;

/**
 * class for saving and loading data to/from file
 * @author Rekin
 *
 */
public class DataSaverLoader {
	private String loadedData;
	
	/**
	 * method for saving game state to file
	 * @param eng Engine from which data will be used to save
	 * @return true if save was successful otherwise false
	 */
	public boolean saveGameState(Engine eng){
		String data = prepareData(eng);
		FilesManager fm = new FilesManager();
		return fm.saveToFile(data);
	}
	
	/**
	 * method for loading game state from file
	 * @param eng Engine to which data will be parsed
	 * @return true if load was successful otherwise false
	 */
	public boolean loadGameState(Engine eng){
		return parseDataToEngine(loadedData, eng);
	}
	
	/**
	 * method for preparing TempUserSetting from a given data from file
	 * @param settings TempUserSettings that will be changed
	 * @return true if successfully loaded data to settings object
	 */
	public boolean prepareSettings(TempUserSettings settings){
		FilesManager fm = new FilesManager();
		loadedData = fm.loadFromFile();
		if(loadedData==null)
			return false;
		else{
			int pnum;
			String pnam;
			if((pnum=getPlayerNum())>0){
				settings.setPlayerNumer(pnum);
			}
			else{
				return false;
			}
			if((pnam=getPlayerName())!=null){
				settings.setPlayerName(pnam);
			}
			else{
				return false;
			}
			return true;
		}
	}
	
	/**
	 * finds player number in data from file
	 * @return player number or -1 if error
	 */
	private int getPlayerNum(){
		int lineInd = loadedData.indexOf("Number");
		int symbolMoreInd = loadedData.indexOf(">", lineInd);
		int symbolNLInd = loadedData.indexOf("\n", lineInd);
		int pnum = -1;
		try{
			pnum = Integer.parseInt(loadedData.substring(symbolMoreInd+1, symbolNLInd));
		}
		catch(NumberFormatException e){
			System.err.println("Error: can't read player number");
		}
		return pnum;
	}
	
	/**
	 * finds player name in data from file
	 * @return player name or null if error
	 */
	private String getPlayerName(){
		int lineInd = loadedData.indexOf("<Name>");
		int symbolMoreInd = loadedData.indexOf(">", lineInd);
		int symbolNLInd = loadedData.indexOf("\n", lineInd);
		String pnam = null;
		pnam=loadedData.substring(symbolMoreInd+1, symbolNLInd);
		return pnam;
	}
	
	/**
	 * prepares data from given Engine to be saved
	 * @param en Engine, from where data will be fetched
	 * @return String representing game data to be saved
	 */
	private String prepareData(Engine en){
		StringBuffer data = new StringBuffer();
		data.append("<Number>"+en.getPlayerNumber()+"\n");
		data.append("<Deck>"+"\n");
		int[][] cardDeck = en.getCardDeck();
		for(int i=0;i<cardDeck.length;++i){
			for(int j=0;j<cardDeck[0].length;++j){
				data.append(cardDeck[i][j]+" ");
			}
			data.append("\n");
		}
		for(int i=0;i<en.getPlayerNumber();++i){
			data.append("<Player>"+"\n");
			data.append("<Name>"+en.getPlayer(i).getName()+"\n");
			data.append("<Money>"+en.getPlayer(i).getMoney()+"\n");
			for(int j=0;j<5;++j){
				data.append("<Card>"+en.getPlayer(i).getCard(j).getColor()+" "+en.getPlayer(i).getCard(j).getFigure() +"\n");
			}
		}
		return data.toString();
	}
	
	/**
	 * parses given data to given Engine
	 * @param data data from file
	 * @param en Engine where data will be put
	 * @return true is success otherwise false
	 */
	private boolean parseDataToEngine(String data, Engine en){
		en.setCardDeck(prepareCardDeckData(data));
		en.setMoneyOnBoard(en.getPlayerNumber()*Engine.defaultEntryFee);
		
		int searchIndex = 0;
		for(int i=0;i<en.getPlayerNumber();++i){
			int indPlayerStart = data.indexOf("<Player>", searchIndex);
			int indPlayerEnd = data.indexOf("<Player>", indPlayerStart+5);
			if(indPlayerEnd<0){ //reached end of file with no <Player> tag
				indPlayerEnd=data.length();
			}
			String playerData = data.substring(indPlayerStart, indPlayerEnd);
			searchIndex = indPlayerEnd-5;
			preparePlayerData(playerData, i, en);
		}
		return true;
	}
	
	/**
	 * prepares card deck from file data
	 * @param data data from file
	 * @return table of int[][] representing card deck
	 */
	private int[][] prepareCardDeckData(String data){
		int indStart = data.indexOf("<Deck>") + 7;
		int indEnd = data.indexOf("<Player>", indStart);
		String deckData = data.substring(indStart, indEnd);
		int[][] deck = new int[4][13];
		String val;
		int searchIndex = 0;
		for(int i=0;i<4;++i){
			for(int j=0;j<13;++j){
				val=deckData.substring(searchIndex, searchIndex+2).trim();
				searchIndex+=2;
				deck[i][j]=Integer.parseInt(val);
			}
			searchIndex+=1; //new line is one char
		}
		return deck;
	}
	
	/**
	 * parses player data to engine
	 * @param playerData extracted from file data about players
	 * @param playerIndex index of player taken into account
	 * @param en engine where data will be put
	 */
	private void preparePlayerData(String playerData, int playerIndex, Engine en){
		int lineInd = playerData.indexOf("<Money>");
		int symbolMoreInd = playerData.indexOf(">", lineInd);
		int symbolNLInd = playerData.indexOf("\n", lineInd);
		String money = playerData.substring(symbolMoreInd+1, symbolNLInd);
		int intMoney = Integer.parseInt(money);
		en.getPlayer(playerIndex).setMoney(intMoney);
		
		int searchIndex = 0;
		for(int i=0;i<5;++i){ //5 cards
			int indCardStart = playerData.indexOf("<Card>", searchIndex);
			int indCardEnd = playerData.indexOf("<Card>", indCardStart+5);
			if(indCardEnd<0){ //reached end of file with no <Player> tag
				indCardEnd=playerData.length();
			}
			String cardData = playerData.substring(indCardStart+("<Card>".length()), indCardEnd);
			searchIndex = indCardEnd-5;
			int cardCol = Integer.parseInt(cardData.substring(0, 2).trim());
			int cardFig = Integer.parseInt(cardData.substring(2, 4).trim());
			en.getPlayer(playerIndex).getCard(i).setFigure(cardFig);
			en.getPlayer(playerIndex).getCard(i).setColor(cardCol);
		}
	}
}
